package com.googlecode.monitoring.flash.dao;

import com.googlecode.monitoring.dao.AgentStatusDao;
import com.googlecode.monitoring.dao.XmlUtils;
import com.googlecode.monitoring.exception.DataDaoException;
import com.googlecode.monitoring.flash.model.FlashItemToCheck;
import com.googlecode.monitoring.model.ItemToCheck;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Repository;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.FileNotFoundException;
import java.util.*;


@Repository
public class XmlFlashAgentStatusDao implements AgentStatusDao {

    Logger log = Logger.getLogger(XmlFlashAgentStatusDao.class);
    private Resource xmlFlashStatusResource;
    private XmlUtils xmlUtils;
    private FlashAgentXmlUtils flashAgentXmlUtils;
    private SchedulerFactoryBean schedulerFactoryBean;

    @Autowired
    public void setXmlUtils(XmlUtils xmlUtils) {
        this.xmlUtils = xmlUtils;
    }

    @Autowired
    public void setXmlFlashStatusResource(Resource xmlFlashStatusResource) {
        this.xmlFlashStatusResource = xmlFlashStatusResource;
    }

    public Resource getXmlFlashStatusResource() {
        return xmlFlashStatusResource;
    }

    @Autowired(required = false)
    public void setSchedulerFactoryBean(SchedulerFactoryBean scheduler) {
        this.schedulerFactoryBean = scheduler;
    }

    @Autowired
    public void setFlashAgentXmlUtils(FlashAgentXmlUtils flashAgentXmlUtils) {
        this.flashAgentXmlUtils = flashAgentXmlUtils;
    }

    @Override
    public boolean saveItemToCheckReport(ItemToCheck item) {
        try {
            Set<ItemToCheck> reportItems;
            try {
                reportItems = new HashSet<ItemToCheck>(getAllItemsFromCheckReport());
            } catch (FileNotFoundException e) {
                reportItems = new HashSet<ItemToCheck>(1);
            }
            reportItems.remove(item);
            reportItems.add(item);
            saveFlashItemsToCheckReport(reportItems);
            return true;
        }
        catch (Exception e) {
            log.error(" error with saving item = " + item, e);
            throw new DataDaoException(" error with saving item = " + item, e);
        }
    }

    @Override
    public List<ItemToCheck> getAllItemsFromCheckReport() throws DataDaoException, FileNotFoundException {
        try {
            Document doc = xmlUtils.getDocumentFromResource(xmlFlashStatusResource);
            NodeList nodes = doc.getElementsByTagName("item");
            List<ItemToCheck> items = new ArrayList<ItemToCheck>();
            log.debug("read " + nodes.getLength() + " nodes item");
            for (int i = 0; i < nodes.getLength(); i++) {
                Node xmlItem = nodes.item(i);
                if (xmlItem.getNodeType() == Node.ELEMENT_NODE) {
                    try {
                        items.add(buildDataToCheckFromStatus((Element) xmlItem));
                    } catch (Exception e) {
                        log.error(xmlItem.toString() + ";i=" + i, e);
                        throw new DataDaoException(xmlItem.toString(), e);
                    }
                }
            }
            return items;
        } catch (Throwable e) {
            throw new DataDaoException(e);
        }
    }

    @Override
    public ItemToCheck getItemFromCheckReport(ItemToCheck itemToCheck) throws DataDaoException {
        try {
            Document doc = xmlUtils.getDocumentFromResource(xmlFlashStatusResource, true);
            XPath xpath = XPathFactory.newInstance().newXPath();
            XPathExpression exprChildOfItem = xpath.compile("document/item[@id='" + itemToCheck.getId() + "']");
            Node flashItemNode = (Node) exprChildOfItem.evaluate(doc, XPathConstants.NODE);
            if (flashItemNode != null) {
                return flashAgentXmlUtils.buildDataToCheck((Element) flashItemNode);
            }
        } catch (Throwable e) {
            throw new DataDaoException(e);
        }
        return null;
    }

    private void saveFlashItemsToCheckReport(Collection<ItemToCheck> reportItems) throws Exception {
        Document doc = xmlUtils.createDoc();
        Element root = (Element) doc.getElementsByTagName("document").item(0);
        for (ItemToCheck item : reportItems) {
            root.appendChild(flashAgentXmlUtils.buildFlashItemToCheckElement(doc, (FlashItemToCheck) item, schedulerFactoryBean));
        }
        xmlUtils.saveDocument(doc, xmlFlashStatusResource);
    }

    private FlashItemToCheck buildDataToCheckFromStatus(Element xmlItemElement) {
        FlashItemToCheck flashItemToCheck = flashAgentXmlUtils.buildDataToCheck(xmlItemElement);
        Node stateNode = xmlItemElement.getElementsByTagName("state").item(0);
        flashItemToCheck.setCurrentStateName(xmlUtils.buildState(stateNode));
        Node nextCheckTimeNode = xmlItemElement.getElementsByTagName("nextCheckTime").item(0);
        flashItemToCheck.setNextCheckTime(xmlUtils.buildCheckTime(nextCheckTimeNode));
        Node lastCheckTimeNode = xmlItemElement.getElementsByTagName("lastCheckTime").item(0);
        flashItemToCheck.setLastCheckTime(xmlUtils.buildCheckTime(lastCheckTimeNode));
        return flashItemToCheck;
    }

}
